import fs from 'node:fs'
import path from 'node:path'
import { dirname } from 'dirname-filename-esm'
import { Client } from 'ssh2'

const __dirname = dirname(import.meta)
// server info
const server = {
  host: '47.245.58.236',
  port: 22,
  username: 'root',
  password: 'tsDJ%%d876erTTR'
}
// 本地项目路径和远程路径
const localDir = path.join(__dirname, 'dist') // 本地项目目录
const remoteDir = '/mnt/prodaping' // 远程服务器目录

// 创建 SSH 客户端实例
const sshClient = new Client()

// 删除远程目录及其内容（递归）
async function deleteRemoteDir(sftp, remotePath) {
  return new Promise((resolve, reject) => {
    sftp.readdir(remotePath, async (err, list) => {
      if (err && err.code === 2) {
        console.log(`远程目录不存在：${remotePath}`)
        return resolve() // 如果目录不存在，直接返回
      } else if (err) {
        return reject(err)
      }

      try {
        for (const item of list) {
          const remoteItemPath = path.join(remotePath, item.filename).replace(/\\/g, '/')

          if (item.longname.startsWith('d')) {
            // 如果是目录，递归删除
            await deleteRemoteDir(sftp, remoteItemPath)
          } else {
            // 如果是文件，直接删除
            await new Promise((res, rej) => {
              sftp.unlink(remoteItemPath, (err) => {
                if (err) rej(err)
                else {
                  console.log(`远程文件已删除：${remoteItemPath}`)
                  res()
                }
              })
            })
          }
        }

        // 删除当前目录
        sftp.rmdir(remotePath, (err) => {
          if (err) reject(err)
          else {
            console.log(`远程目录已删除：${remotePath}`)
            resolve()
          }
        })
      } catch (e) {
        reject(e)
      }
    })
  })
}

// 上传文件
async function uploadFile(sftp, localPath, remotePath) {
  return new Promise((resolve, reject) => {
    sftp.fastPut(localPath, remotePath, (err) => {
      if (err) {
        reject(err)
      } else {
        console.log(`文件 ${localPath} 上传成功到 ${remotePath}`)
        resolve()
      }
    })
  })
}

// 创建远程目录（如果不存在）
async function createRemoteDirIfNotExist(sftp, remoteDir) {
  return new Promise((resolve, reject) => {
    sftp.stat(remoteDir, (err, stats) => {
      if (err && err.code === 2) {
        // 如果目录不存在，err.code 会是 2
        console.log(`远程目录不存在，正在创建：${remoteDir}`)
        sftp.mkdir(remoteDir, { recursive: true }, (err) => {
          if (err) {
            reject(err)
          } else {
            console.log(`远程目录 ${remoteDir} 创建成功`)
            resolve()
          }
        })
      } else if (err) {
        reject(err)
      } else {
        resolve() // 目录已存在，继续
      }
    })
  })
}

// 递归上传目录
async function uploadDirectory(sftp, localPath, remotePath) {
  const items = await fs.promises.readdir(localPath, { withFileTypes: true })

  for (const item of items) {
    const localItemPath = path.join(localPath, item.name)
    const remoteItemPath = path.join(remotePath, item.name).replace(/\\/g, '/') // 替换反斜杠为正斜杠

    if (item.isDirectory()) {
      // 如果是目录，递归创建并上传
      await createRemoteDirIfNotExist(sftp, remoteItemPath)
      await uploadDirectory(sftp, localItemPath, remoteItemPath)
    } else if (item.isFile()) {
      // 如果是文件，上传文件
      await uploadFile(sftp, localItemPath, remoteItemPath)
    }
  }
}

// 部署项目
async function deployProject() {
  try {
    await new Promise((resolve, reject) => {
      sshClient
        .on('ready', () => {
          console.log('SSH连接成功')

          sshClient.sftp(async (err, sftp) => {
            if (err) {
              reject(`SFTP连接失败: ${err}`)
              return
            }

            if (!sftp || typeof sftp.fastPut !== 'function') {
              reject('SFTP客户端没有正确初始化，或者 fastPut 方法不存在')
              return
            }

            try {
              // 如果远程目录存在，先递归删除
              console.log(`检查并删除远程目录：${remoteDir}`)
              await deleteRemoteDir(sftp, remoteDir)

              // 创建远程根目录
              await createRemoteDirIfNotExist(sftp, remoteDir)

              // 开始递归上传目录
              await uploadDirectory(sftp, localDir, remoteDir)

              resolve()
            } catch (e) {
              reject(e)
            }
          })
        })
        .on('error', (err) => {
          reject(`SSH连接失败: ${err}`)
        })
        .connect(server)
    })
  } catch (err) {
    console.error('部署过程中出现错误:', err)
  }
}

deployProject()
